package com.gca.airhockey;

import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.camera.Camera;
import org.anddev.andengine.engine.options.EngineOptions;
import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.anddev.andengine.entity.primitive.Rectangle;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.scene.Scene.IOnAreaTouchListener;
import org.anddev.andengine.entity.scene.Scene.IOnSceneTouchListener;
import org.anddev.andengine.entity.scene.Scene.ITouchArea;
import org.anddev.andengine.entity.scene.background.ColorBackground;
import org.anddev.andengine.entity.shape.IShape;
import org.anddev.andengine.entity.shape.Shape;
import org.anddev.andengine.entity.sprite.AnimatedSprite;
import org.anddev.andengine.entity.util.FPSLogger;
import org.anddev.andengine.extension.physics.box2d.PhysicsConnector;
import org.anddev.andengine.extension.physics.box2d.PhysicsFactory;
import org.anddev.andengine.extension.physics.box2d.PhysicsWorld;
import org.anddev.andengine.extension.physics.box2d.util.Vector2Pool;
import org.anddev.andengine.extension.physics.box2d.util.constants.PhysicsConstants;
import org.anddev.andengine.input.touch.TouchEvent;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.anddev.andengine.opengl.texture.region.TiledTextureRegion;
import org.anddev.andengine.sensor.accelerometer.AccelerometerData;
import org.anddev.andengine.sensor.accelerometer.IAccelerometerListener;
import org.anddev.andengine.ui.activity.BaseGameActivity;
import org.anddev.andengine.util.Debug;

import android.hardware.SensorManager;
import android.widget.Toast;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.joints.MouseJoint;
import com.badlogic.gdx.physics.box2d.joints.MouseJointDef;

/**
 * @author albrandroid
 * @author Nicolas Gramlich
 * @since 10:35:23 - 28.02.2011
 */
public class AirHockeyActivity extends BaseGameActivity implements IAccelerometerListener, IOnSceneTouchListener, IOnAreaTouchListener {
        // ===========================================================
        // Constants
        // ===========================================================

        private static final int CAMERA_WIDTH = 720;
        private static final int CAMERA_HEIGHT = 480;

        private static final FixtureDef FIXTURE_DEF = PhysicsFactory.createFixtureDef(1, 0.5f, 0.5f);

        // ===========================================================
        // Fields
        // ===========================================================

        private BitmapTextureAtlas mBitmapTextureAtlas;

        private TiledTextureRegion mBoxFaceTextureRegion;
        private TiledTextureRegion mCircleFaceTextureRegion;

        private Scene mScene;

        private PhysicsWorld mPhysicsWorld;
        private int mFaceCount = 0;

        private MouseJoint mMouseJointActive;
        private Body mGroundBody;

        // ===========================================================
        // Constructors
        // ===========================================================

        // ===========================================================
        // Getter & Setter
        // ===========================================================

        // ===========================================================
        // Methods for/from SuperClass/Interfaces
        // ===========================================================

        @Override
        public Engine onLoadEngine() {
                Toast.makeText(this, "Touch the screen to add objects.", Toast.LENGTH_LONG).show();
                final Camera camera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
                final EngineOptions engineOptions = new EngineOptions(true, ScreenOrientation.LANDSCAPE, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), camera);
                engineOptions.getTouchOptions().setRunOnUpdateThread(true);
                return new Engine(engineOptions);
        }

        @Override
        public void onLoadResources() {
                /* Textures. */
                this.mBitmapTextureAtlas = new BitmapTextureAtlas(64, 64, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
                BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");

                /* TextureRegions. */
                this.mBoxFaceTextureRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mBitmapTextureAtlas, this, "face_box_tiled.png", 0, 0, 2, 1); // 64x32
                this.mCircleFaceTextureRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mBitmapTextureAtlas, this, "face_circle_tiled.png", 0, 32, 2, 1); // 64x32
                this.mEngine.getTextureManager().loadTexture(this.mBitmapTextureAtlas);
        }

        @Override
        public Scene onLoadScene() {
                this.mEngine.registerUpdateHandler(new FPSLogger());
                
                this.mScene = new Scene();
                this.mScene.setBackground(new ColorBackground(0, 0, 0));
                this.mScene.setOnSceneTouchListener(this);
                this.mScene.setOnAreaTouchListener(this);

                this.mPhysicsWorld = new PhysicsWorld(new Vector2(0, SensorManager.GRAVITY_EARTH), false);
                this.mGroundBody = this.mPhysicsWorld.createBody(new BodyDef());

                final Shape ground = new Rectangle(0, CAMERA_HEIGHT - 2, CAMERA_WIDTH, 2);
                final Shape roof = new Rectangle(0, 0, CAMERA_WIDTH, 2);
                final Shape left = new Rectangle(0, 0, 2, CAMERA_HEIGHT);
                final Shape right = new Rectangle(CAMERA_WIDTH - 2, 0, 2, CAMERA_HEIGHT);

                final FixtureDef wallFixtureDef = PhysicsFactory.createFixtureDef(0, 0.5f, 0.5f);
                PhysicsFactory.createBoxBody(this.mPhysicsWorld, ground, BodyType.StaticBody, wallFixtureDef);
                PhysicsFactory.createBoxBody(this.mPhysicsWorld, roof, BodyType.StaticBody, wallFixtureDef);
                PhysicsFactory.createBoxBody(this.mPhysicsWorld, left, BodyType.StaticBody, wallFixtureDef);
                PhysicsFactory.createBoxBody(this.mPhysicsWorld, right, BodyType.StaticBody, wallFixtureDef);

                this.mScene.attachChild(ground);
                this.mScene.attachChild(roof);
                this.mScene.attachChild(left);
                this.mScene.attachChild(right);
                addFace(0f,0f);
                this.mScene.registerUpdateHandler(this.mPhysicsWorld);

                return this.mScene;
        }

        @Override
        public void onLoadComplete() {
                this.mEngine.enableVibrator(this);
        }

        @Override
        public boolean onSceneTouchEvent(final Scene pScene, final TouchEvent pSceneTouchEvent) {
                if(this.mPhysicsWorld != null) {
                        switch(pSceneTouchEvent.getAction()) {
                                case TouchEvent.ACTION_DOWN:
                                       
                                        return true;
                                case TouchEvent.ACTION_MOVE:
                                        if(this.mMouseJointActive != null) {
                                                final Vector2 vec = Vector2Pool.obtain(pSceneTouchEvent.getX() / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT, pSceneTouchEvent.getY() / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT);
                                                this.mMouseJointActive.setTarget(vec);
Log.v("vecteur",vec.toString());
                                                Vector2Pool.recycle(vec);
                                        }
                                        return true;
                                case TouchEvent.ACTION_UP:
                                        if(this.mMouseJointActive != null) {
                                                this.mPhysicsWorld.destroyJoint(this.mMouseJointActive);
                                                this.mMouseJointActive = null;
                                        }
                                        return true;
                        }
                        return false;
                }
                return false;
        }

        @Override
        public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final ITouchArea pTouchArea, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
                if(pSceneTouchEvent.isActionDown()) {
                        final IShape face = (IShape) pTouchArea;
                        /*
                         * If we have a active MouseJoint, we are just moving it around
                         * instead of creating a second one.
                         */
                        if(this.mMouseJointActive == null) {
                                //this.mEngine.vibrate(100);
                                this.mMouseJointActive = this.createMouseJoint(face, pTouchAreaLocalX, pTouchAreaLocalY);
                        }
                        return true;
                }
                return false;
        }

        @Override
        public void onAccelerometerChanged(final AccelerometerData pAccelerometerData) {
                final Vector2 gravity = Vector2Pool.obtain(pAccelerometerData.getX(), pAccelerometerData.getY());
                this.mPhysicsWorld.setGravity(gravity);
                Vector2Pool.recycle(gravity);
        }

        @Override
        public void onResumeGame() {
                super.onResumeGame();

                this.enableAccelerometerSensor(this);
        }

        @Override
        public void onPauseGame() {
                super.onPauseGame();

                this.disableAccelerometerSensor();
        }

        // ===========================================================
        // Methods
        // ===========================================================

        public MouseJoint createMouseJoint(final IShape pFace, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
                final Body body = (Body) pFace.getUserData();
                final MouseJointDef mouseJointDef = new MouseJointDef();

                final Vector2 localPoint = Vector2Pool.obtain((pTouchAreaLocalX - pFace.getWidth() * 0.5f) / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT, (pTouchAreaLocalY - pFace.getHeight() * 0.5f) / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT);
                this.mGroundBody.setTransform(localPoint, 0);

                mouseJointDef.bodyA = this.mGroundBody;
                mouseJointDef.bodyB = body;
                mouseJointDef.dampingRatio = 0.95f;
                mouseJointDef.frequencyHz = 30;
                mouseJointDef.maxForce = (200.0f * body.getMass());
                mouseJointDef.collideConnected = true;

                mouseJointDef.target.set(body.getWorldPoint(localPoint));
                Vector2Pool.recycle(localPoint);

                return (MouseJoint) this.mPhysicsWorld.createJoint(mouseJointDef);
        }

        private void addFace(final float pX, final float pY) {
                this.mFaceCount++;
                Debug.d("Faces: " + this.mFaceCount);

                final AnimatedSprite face;
                final Body body;

                if(this.mFaceCount % 2 == 0) {
                        face = new AnimatedSprite(pX, pY, this.mBoxFaceTextureRegion);
                        body = PhysicsFactory.createBoxBody(this.mPhysicsWorld, face, BodyType.DynamicBody, FIXTURE_DEF);
                } else {
                        face = new AnimatedSprite(pX, pY, this.mCircleFaceTextureRegion);
                        body = PhysicsFactory.createCircleBody(this.mPhysicsWorld, face, BodyType.DynamicBody, FIXTURE_DEF);
                }
                face.setUserData(body);
                face.animate(200);

                this.mScene.registerTouchArea(face);
                this.mScene.attachChild(face);

                this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(face, body, true, true));
        }

        // ===========================================================
        // Inner and Anonymous Classes
        // ===========================================================
}